package de.pyranja.timing;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import com.google.common.base.Ticker;

/**
 * A ticker that updates it's time in periodic intervals.
 * 
 * @author Chris Borckholder
 */
public class CachingTicker extends Ticker {

	// 1 second default interval
	private static final long DEF_INTERVAL = 
			TimeUnit.SECONDS.toNanos(1L);
	
	private static final long DEF_DELAY = 0L;
	
	// cached time
	private final AtomicLong now;
	// time fetch task
	private volatile ScheduledFuture<?> timeTask;
	// flags if started
	private volatile boolean started;
	// interval between time updates
	private long interval;
	// thread pool used
	private ScheduledExecutorService scheduler;
	
	public CachingTicker() {
		now = new AtomicLong();
		interval = DEF_INTERVAL;
		
	}
	
	@Override
	public long read() {
		return now.get();
	}

	// lifecycle hooks
	public synchronized void start() {
		if (started) {
			throw new IllegalStateException("Already started.");
		}
		final Runnable updateTime = new Runnable() {
			public void run() {
				now.set(System.nanoTime());
			}
		};
		now.set(System.nanoTime());
		this.timeTask = scheduler.scheduleAtFixedRate(updateTime, DEF_DELAY, interval, TimeUnit.NANOSECONDS);
		started = true;
	}
	
	public synchronized void stop() {
		if (started) {
			timeTask.cancel(true);
		} else {
			throw new IllegalStateException("Not started.");
		}
	}
	
	// injection
	
	/**
	 * @param scheduler scheduler execution service used
	 */
	public void setScheduler(ScheduledExecutorService scheduler) {
		this.scheduler = scheduler;
	}

	/**
	 * @param interval the interval to set
	 */
	public void setIntervalAsNanos(Long interval) {
		this.interval = interval;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "CachingTicker [started=" + started + ", interval=" + interval
				+ ", scheduler=" + scheduler + "]";
	}
}
